package com.winit.openapi.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.winit.openapi.model.ParameterAdapterEntity;
import com.winit.openapi.model.RequestMsg;
import com.winit.openapi.model.ResponseMsg;

/**
 * openapi参数适配类：统一适配API输入输出参数
 * 
 * 参数模板文件在parameter文件夹下，支持xls,xlsx格式的文件。
 * 如果要加薪的接口适配，请按模板文件添加相应的接口适配信息。模板中标红的列是必填。
 * 
 * @version <pre>
 * Author	Version		Date		Changes
 * minghao.deng 	1.0  		2016年7月11日 	Created
 *
 * </pre>
 * @since 1.
 */
public class ParameterAdapterUtils {

    private static final String PARA_RESOURCE_PATH = "parameter";
    private static final String OFFICE_EXCEL_2003_POSTFIX = "xls";
    private static final String OFFICE_EXCEL_2010_POSTFIX = "xlsx";
    private static final String POINT = ".";
    private static final String PARAMETER_TYPE_INPUT = "input";
    private static final String PARAMETER_TYPE_OUTPUT = "output";
    private static final Logger logger = LoggerFactory.getLogger(ParameterAdapterUtils.class);

    private static Map<String, List<ParameterAdapterEntity>> paraDict = new HashMap<String, List<ParameterAdapterEntity>>();

    static {
        initParaDict();
    }

    /**
     * 转换入参参数名称
     * 
     * @param request
     */
    public static RequestMsg handleInputAdapte(RequestMsg requestMsg) {
        String action = requestMsg.getAction();
        Object obj = requestMsg.getData();
        if (null == obj) {
            return requestMsg;
        }
        logger.info("openapi参数入参转换前：action名称：{}，版本：{}，data:{}", requestMsg.getAction(), requestMsg.getVersion(),
                requestMsg.getData());
        String json = JSON.toJSONString(requestMsg);
        String adaptedRes = replaceJsonKey(json, action, PARAMETER_TYPE_INPUT);
        JSONObject jsonRes = JSONObject.parseObject(adaptedRes);
        RequestMsg requestRes = JSONObject.toJavaObject(jsonRes, RequestMsg.class);
        if (null != requestRes) {
            logger.info("openapi参数入参转换结果：action名称：{}，版本：{}，data:{}", requestMsg.getAction(), requestMsg.getVersion(),
                    requestRes.getData());
            return requestRes;
        }
        return requestMsg;

    }

    /**
     * API 2.0返回参数适配
     * 
     * @param requestMsg 请求的request数据封装对象
     * @param responseMsg 请求的response数据封装对象
     */
    public static ResponseMsg handleOutputAdapte(RequestMsg requestMsg, ResponseMsg responseMsg) {
        // 版本是2.0的才需要适配，1.0或者version不填都认为是1.0版本
        String action = requestMsg.getAction();
        logger.info("openapi参数出参转换前：action名称：{}，版本：{}，data:{}", requestMsg.getAction(), requestMsg.getVersion(),
                responseMsg.getData());
        String json = JSON.toJSONString(responseMsg);
        String adaptedRes = replaceJsonKey(json, action, PARAMETER_TYPE_OUTPUT);
        JSONObject jsonRes = JSONObject.parseObject(adaptedRes);
        ResponseMsg responseRes = JSONObject.toJavaObject(jsonRes, ResponseMsg.class);
        if (null != responseRes) {
            logger.info("openapi参数出参转换结果：action名称：{}，版本：{}，data:{}", requestMsg.getAction(), requestMsg.getVersion(),
                    responseMsg.getData());
            return responseRes;
        }
        return responseMsg;

    }

    /**
     * 适配返回报错的Msg对象，主要是报xx字段不能为空
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    public static String handleResponseMsg(String msg, String action) {
        if (StringUtils.isEmpty(msg)) {
            return msg;
        }
        return replaceJsonKey(msg, action, null);
    }

    private static String replaceJsonKey(String inputStr, String action, String type) {
        List<ParameterAdapterEntity> list = paraDict.get(action);
        if (CollectionUtils.isEmpty(list)) {
            return inputStr;
        }
        String result = inputStr;
        // 输入参数适配
        if (PARAMETER_TYPE_INPUT.equals(type)) {
            for (ParameterAdapterEntity entity : list) {

                if (inputStr.contains(entity.getAdaptedName()) && PARAMETER_TYPE_INPUT.equals(entity.getType())) {
                    result = result.replaceAll(entity.getAdaptedName(), entity.getOriginalName());
                }
            }
            // 输出参数适配
        } else if (PARAMETER_TYPE_OUTPUT.equals(type)) {
            for (ParameterAdapterEntity entity : list) {

                if (inputStr.contains(entity.getOriginalName()) && PARAMETER_TYPE_OUTPUT.equals(entity.getType())) {
                    result = result.replaceAll(entity.getOriginalName(), entity.getAdaptedName());
                }
            }
        } else {
            for (ParameterAdapterEntity entity : list) {

                if (inputStr.contains(entity.getOriginalName())) {
                    result = result.replaceAll(entity.getOriginalName(), entity.getAdaptedName());
                }
            }
        }

        return result;
    }

    private static void initParaDict() {
        logger.info("参数适配初始化开始,读取初始化文件路径：{}", PARA_RESOURCE_PATH);
        try {
            List<ParameterAdapterEntity> paraList = readExcel(PARA_RESOURCE_PATH);
            if (CollectionUtils.isEmpty(paraList)) {
                return;
            }
            for (ParameterAdapterEntity parameterAdapterEntity : paraList) {
                String actionName = parameterAdapterEntity.getActionName();
                if (!paraDict.containsKey(actionName)) {
                    List<ParameterAdapterEntity> list = new ArrayList<ParameterAdapterEntity>();
                    list.add(parameterAdapterEntity);
                    paraDict.put(actionName, list);
                } else {
                    paraDict.get(actionName).add(parameterAdapterEntity);
                }
            }
        } catch (IOException e) {
            logger.error("初始化参数适配失败！");
        }
        logger.info("参数适配初始化结束");
    }

    private static List<ParameterAdapterEntity> readExcel(String path) throws IOException {
        if (StringUtils.isEmpty(path)) {
            logger.error("读取参数适配文件路径失败.");
            return null;
        }

        String filePath = ParameterAdapterUtils.class.getClassLoader().getResource("").getPath() + path;
        File dirFile = new File(filePath);
        File[] tempList = dirFile.listFiles();

        if (null == tempList || 0 == tempList.length) {
            logger.error("读取参数适配文件路径失败,不存在该文件");
            return null;
        }
        String fileName = null;
        for (File file : tempList) {
            if (file.isFile()) {
                //只读取第一个文件
                fileName = file.getName();
                break;
            }
        }
        // 获取文件后缀名xls xlsx
        String postfix = getPostfix(fileName);
        if (StringUtils.EMPTY.equals(postfix)) {
            logger.error("参数适配文件格式不支持.");
            return null;
        } else if (!OFFICE_EXCEL_2010_POSTFIX.equals(postfix) && !OFFICE_EXCEL_2003_POSTFIX.equals(postfix)) {
            logger.error("参数适配文件格式不支持.");
            return null;
        }
        Workbook wb = null;
        InputStream in = null;
        try {
            in = new FileInputStream(filePath + File.separator + fileName);
            if (OFFICE_EXCEL_2003_POSTFIX.equals(postfix)) {
                wb = new HSSFWorkbook(in);
            } else {
                wb = new XSSFWorkbook(in);

            }
            return readXls(wb);
        } catch (Exception e) {
            logger.error("文件处理异常，异常信息为:" + e);
        } finally {
            try {
                if (null != in) {
                    in.close();
                }
            } catch (IOException e) {
                logger.error("流关闭处理异常，异常信息为: " + e);
            }
        }

        return null;
    }

    private static List<ParameterAdapterEntity> readXls(Workbook wb) {

        Sheet sheet = wb.getSheetAt(0);
        int rowNum = sheet.getLastRowNum();
        List<ParameterAdapterEntity> paraList = new ArrayList<ParameterAdapterEntity>();
        // 过滤掉第一行的标题行
        for (int i = 1; i <= rowNum; i++) {
            ParameterAdapterEntity para = new ParameterAdapterEntity();
            Row row = sheet.getRow(i);
            if (null != row) {
                String actionName = getStringNoBlank(row.getCell(0));
                String actionDesc = getStringNoBlank(row.getCell(1));
                String originalName = getStringNoBlank(row.getCell(2));
                String adaptedName = getStringNoBlank(row.getCell(3));
                String type = getStringNoBlank(row.getCell(4));
                String source = getStringNoBlank(row.getCell(5));
                String paraDesc = getStringNoBlank(row.getCell(6));
                para.setActionName(actionName);
                para.setActionDesc(actionDesc);
                para.setOriginalName(originalName);
                para.setAdaptedName(adaptedName);
                para.setType(type);
                para.setSource(source);
                para.setParaDesc(paraDesc);

                paraList.add(para);
            }
        }

        return paraList;

    }

    private static String getPostfix(String path) {
        if (StringUtils.isEmpty(path)) {
            return StringUtils.EMPTY;
        }
        if (path.contains(POINT)) {
            return path.substring(path.lastIndexOf(POINT) + 1, path.length());
        }
        return StringUtils.EMPTY;
    }

    private static String getStringNoBlank(Cell cell) {
        if (null == cell) {
            return null;
        }
        String inputStr = cell.getStringCellValue();
        if (StringUtils.isEmpty(inputStr)) {
            return null;
        }
        return inputStr.trim();
    }

    public static void main(String[] args) throws IOException {
        // readExcel("F:\\excel");

    }

}
